/******************************************************************
 * Copyright @ 2023 Gim. All rights reserverd.
 * @file   src\configuration\index.ts
 * @author Gim
 * @date   2023/05/30 10:34
 * @desc   配置项
 *    本文件的代码负责读/写配置
 *    配置项在"[workspace]/.vscode/.setting.json"中，
 *    以"torna-api-visitor.XXXXX"开头
 * 
 *    另外一些敏感信息则放在"[workspace]/.vscode/sensitive.json"
 ******************************************************************/

import * as fs from 'node:fs/promises';
import * as vscode from 'vscode';
import { Helper } from '../helper';
import { Memory } from '../memory';
export interface Doc {
  id: string;
  moduleId: string;
  projectId: string;
}
export const section = 'torna-api-visitor';
export type SpaceId = string;
export type ModuleId = string;
export type ProjectId = string;
export type DocumentId = string;
export type Customization = Record<string, string>;
export interface Customizations {
  spaces?: Record<SpaceId, Customization | undefined>;
  modules?: Record<ModuleId, Customization | undefined>;
  projects?: Record<ProjectId, Customization | undefined>;
  documents?: Record<DocumentId, Customization | undefined>;
}
export interface OutputPaths {
  spaces?: Record<SpaceId, string | undefined>;
  modules?: Record<ModuleId, string | undefined>;
  projects?: Record<ProjectId, string | undefined>;
  documents?: Record<DocumentId, string | undefined>;
}
export interface TemplatePaths {
  spaces?: Record<SpaceId, string | undefined>;
  modules?: Record<ModuleId, string | undefined>;
  projects?: Record<ProjectId, string | undefined>;
  documents?: Record<DocumentId, string | undefined>;
}
export function getConfig() {
  return vscode.workspace.getConfiguration(section);
}


/**
 * 保存敏感信息文件名
 * @date 1/24/2024 - 6:54:50 PM
 *
 * @export
 * @param {string} fileName
 * @returns {Thenable<void>}
 */
export function setSensitiveFileName(fileName: string): Thenable<void> {
  return getConfig().update('sensitiveFile', fileName);
}


/**
 * 获取敏感信息文件名
 * @date 1/24/2024 - 6:54:19 PM
 *
 * @export
 * @returns {string} 敏感信息文件名
 */
export function getSensitiveFileName(): string {
  return getConfig().get<string>('sensitiveFile', 'sensitive.json');
}

/**
 * 设置默认输出目录路径
 * 
 * @export
 * @param {string} fsPath 输出目录路径
 * @return {Thenable<void>}
 */
export function setDefaultOutputPath(fsPath: string): Thenable<void> {
  return getConfig().update('output', fsPath);
}

/**
 * 获取默认输出目录路径
 * 
 * @export
 * @return {string} 默认输出目录路径
 */
export function getDefaultOutputPath(): string {
  return getConfig().get<string>('output', '');
}

/**
 * 设置默认模板文件路径
 * 
 * @export
 * @param {string} fsPath 默认模板文件路径
 * @returns {Thenable<void>}
 */
export function setDefaultTemplatePath(fsPath: string): Thenable<void> {
  return getConfig().update('template', fsPath);
}

/**
 * 获取默认模板文件路径
 * 
 * @export
 * @return {string} 默认输出目录路径
 */
export function getDefaultTemplatePath(): string {
  return getConfig().get<string>('template', '');
}

/**
 * 获取指定接口的输出目录路径
 *
 * @export
 * @param {Doc} [doc] 指定接口的相关信息
 * @return {string} 指定接口的输出目录路径
 */
export function getOutputPath(doc?: Doc): string {
  return doc ? (
    findOutputPath('documents', doc.id) ??
    findOutputPath('modules', doc.moduleId) ??
    findOutputPath('projects', doc.projectId) ??
    getDefaultOutputPath()
  ) : getDefaultOutputPath();
}

/**
 * 获取指定接口对应的模板文件路径
 *
 * @export
 * @param {Doc} [doc] 指定接口的相关信息
 * @return {string} 指定接口对应的模板文件路径
 */
export function getTemplatePath(doc?: Doc): string {
  return doc ? (
    findTemplatePath('documents', doc.id) ??
    findTemplatePath('modules', doc.moduleId) ??
    findTemplatePath('projects', doc.projectId) ??
    getDefaultTemplatePath()
  ) : getDefaultTemplatePath();
}

/**
 * 获取指定接口对应的自定义替换信息
 *
 * @export
 * @param {Doc} doc 指定接口的相关信息
 * @return {Customization} 自定义替换信息
 */
export function getCustomization(doc: Doc): Customization {
  return Object.assign({},
    findCustomization('projects', doc.projectId),
    findCustomization('modules', doc.moduleId),
    findCustomization('documents', doc.id)
  );
}

/**
 * 获取全部自定义替换信息
 *
 * @export
 * @return {(Customizations | undefined)} 全部自定义替换信息
 */
export function getCustomizations(): Customizations | undefined {
  const ret = getConfig().get<Customizations>('customizations');
  if (Array.isArray(ret)) {
    console.error('[TAV] getCustomizations()', 'shoud be object, but got array.');
    return;
  } else if (typeof ret !== 'object') {
    console.error(`[TAV] getCustomizations()', 'shoud be object, but got ${typeof ret}.`);
    return;
  }
  return ret;
}

export function findCustomization(level: keyof Customizations, id: SpaceId): Customization | undefined {
  return getCustomizations()?.[level]?.[id];
}
export function getTemplatePaths(): TemplatePaths | undefined {
  return getConfig().get<TemplatePaths>('templates');
}
export function findTemplatePath(level: keyof TemplatePaths, id: SpaceId): string | undefined {
  return getTemplatePaths()?.[level]?.[id];
}
export function getOutputPaths(): OutputPaths | undefined {
  return getConfig().get<OutputPaths>('outputs');
}
export function findOutputPath(level: keyof OutputPaths, id: SpaceId): string | undefined {
  return getOutputPaths()?.[level]?.[id];
}
type SensitiveInfo = {
  // eslint-disable-next-line @typescript-eslint/naming-convention
  "torna-api-visitor.users"?: Memory.IUser[];

  apiInfo?: Record<Memory.UserKey, {
    spaces: Memory.ISpace[];
    projects: Memory.IProject[];
    modules: Memory.IModule[];
    documents: Memory.IDoc[];
  }>;
};
let sensitiveInfo: SensitiveInfo | undefined;
export async function getSensitiveInfoFileUri() {
  const workspace = await Helper.workspace();
  const folder = workspace.uri;
  const sensitiveFile = getSensitiveFileName();
  return vscode.Uri.joinPath(folder!, ".vscode", sensitiveFile);
}

export async function getSensitiveInfo(): Promise<SensitiveInfo> {
  if (sensitiveInfo) { return sensitiveInfo; }
  const uri = await getSensitiveInfoFileUri();
  sensitiveInfo = await fs.readFile(uri.fsPath).then(v => v.toString()).then(v => <SensitiveInfo>JSON.parse(v)).catch(v => ({}));
  return sensitiveInfo;
}

export async function setSensitiveInfo(v: SensitiveInfo): Promise<void> {
  sensitiveInfo = v;
  const uri = await getSensitiveInfoFileUri();
  return fs.writeFile(uri.fsPath, JSON.stringify(v, undefined, 2));
}

export async function getUsers() {
  const sensitiveInfo = await getSensitiveInfo();
  return sensitiveInfo["torna-api-visitor.users"] || [];
}

export async function setUsers(users: Memory.IUser[]) {
  const sensitiveInfo = await getSensitiveInfo();
  sensitiveInfo["torna-api-visitor.users"] = users;
  const userKeys = users.map<Memory.UserKey>(u => Memory.userKey(u));
  Object.keys(sensitiveInfo.apiInfo ?? {}).forEach(a => {
    if (userKeys.some(b => a === b)) { return; }
    delete sensitiveInfo.apiInfo?.[a];
  });
  setSensitiveInfo(sensitiveInfo);
}

export async function addUser(user: Memory.IUser) {
  const users = await getUsers();
  setUsers([
    ...users.filter(v => v.url !== user.url && v.username !== user.username),
    user
  ]);
}

export async function removeUser(username: string, url: string) {
  const users = await getUsers();
  setUsers(users.filter(v => v.url !== url && v.username !== username));
}